package KC.cimaV2;

import java.util.*;

public class AlmacenTree {
    /**
     * Atributo para almacenar objetos de tipo AlmacenNode
     */
    private Object [] almacenes;

    public Object [] almacenes(){
        return almacenes;
    }

    public AlmacenTree( ){
        ArrayList arrL_tmp = new ArrayList();
        almacenes = arrL_tmp.toArray();
    }

    public boolean agregarNodo( AlmacenNode nodo ){
        if (nodo != null) {
            AlmacenNode nodo_tmp = encontrado( nodo );
            int int_tmp = nodo.idAlmacen();
            if( nodo_tmp != null ){
                nodo_tmp.agregarAlmacenesOrigen(nodo.almacenesOrigen());
                return false;
            }else{
                agregarNodoAlmacen( nodo );
                return true;
            }
        } else {
            return false;
        }
    }

    private AlmacenNode encontrado( AlmacenNode nodo ){
        AlmacenNode nodo_retVal = null;
        Iterator itr_tmp = Arrays.asList(almacenes).iterator();
        int int_idAlmacen = nodo.idAlmacen();
        while (itr_tmp.hasNext()) {
            AlmacenNode nodo_tmp = (AlmacenNode) itr_tmp.next();
            int int_idAlmacenTmp = nodo_tmp.idAlmacen();
            if ( int_idAlmacenTmp == int_idAlmacen ) {
                nodo_retVal = nodo_tmp;
                break;
            }
        }
        return nodo_retVal;
    }

    private void agregarNodoAlmacen( AlmacenNode nodo ){
        ArrayList arrL_tmp = new ArrayList(Arrays.asList(almacenes));
        arrL_tmp.add(nodo);
        almacenes = arrL_tmp.toArray();
    }

    public Object [] rutas( ){
        ArrayList arrL_retVal = new ArrayList();
        if( almacenes.length > 0 ){
            AlmacenNode nodo_raiz = (AlmacenNode)almacenes[0];
            Iterator itr_tmp = Arrays.asList(almacenes).iterator();
            while( itr_tmp.hasNext() ){
                ArrayList arrL_rutas = new ArrayList();
                AlmacenNode nodo_tmp = (AlmacenNode)itr_tmp.next();
                if( nodo_tmp.almacenOrigen( nodo_raiz.idAlmacen() ) ){
                    if( !rutas(nodo_tmp, arrL_rutas, "") ){
                        nodo_tmp.tipo(AlmacenNode.HOJA);
                        Object [] objs_ruta = {new Double( nodo_tmp.toneladasOrigen(nodo_raiz.idAlmacen()) ), nodo_tmp.codigoAlmacen(), new Integer(nodo_raiz.idAlmacen()), new Integer(nodo_tmp.idAlmacen()) };
                        arrL_rutas.add(objs_ruta);
                    }
                    Object [] objs_nodos = { nodo_tmp };
                    Object [] objs_subGrupo = {objs_nodos, new Double( nodo_tmp.toneladasDestino(nodo_raiz.idAlmacen()) ), arrL_rutas.toArray() };
                    arrL_retVal.add(objs_subGrupo);
                }
            }
        }
        arrL_retVal = revisarOrigenesMultiples(arrL_retVal);
        return arrL_retVal.toArray();
    }

    private boolean rutas( AlmacenNode nodo, ArrayList arrL_rutas, String str_rutaAnt ){
        boolean bol_retVal = false;
        Iterator itr_tmp = Arrays.asList(almacenes).iterator();
        while( itr_tmp.hasNext() ){
            AlmacenNode nodo_tmp = (AlmacenNode)itr_tmp.next();
            if( nodo_tmp.almacenOrigen( nodo.idAlmacen() ) ){
                bol_retVal = true;
                if( !rutas(nodo_tmp, arrL_rutas, str_rutaAnt + ( str_rutaAnt.equals("") ? "" :  " - " ) + nodo.codigoAlmacen() ) ){
                    nodo_tmp.tipo(AlmacenNode.HOJA);
                    Object [] objs_ruta = {new Double( nodo_tmp.toneladasDestino(nodo.idAlmacen()) ), str_rutaAnt + ( str_rutaAnt.equals("") ? "" :  " - " ) + nodo.codigoAlmacen() + " - " + nodo_tmp.codigoAlmacen(), new Integer(nodo.idAlmacen()), new Integer(nodo_tmp.idAlmacen()) };
                    arrL_rutas.add( objs_ruta );
                }
            }
        }
        return bol_retVal;
    }

    private ArrayList revisarOrigenesMultiples( ArrayList arrL_rutas ){
        ArrayList arrL_retVal = new ArrayList();
        Iterator itr_tmp = Arrays.asList( almacenes ).iterator();
        while( itr_tmp.hasNext() ){
            ArrayList arrL_rutasComunes = new ArrayList();
            AlmacenNode nodo_tmp = (AlmacenNode)itr_tmp.next();
            if( nodo_tmp.tipo() == AlmacenNode.NODOINTERMEDIO && nodo_tmp.almacenesOrigen().length > 1 ){
                Iterator itr_almOrigen = Arrays.asList(nodo_tmp.almacenesOrigen()).iterator();
                while( itr_almOrigen.hasNext() ){
                    int int_almacenInicioR = encontrarInicioRuta( ((AlmacenOrigen)itr_almOrigen.next()).idAlmacen(), nodo_tmp.idAlmacen() );
                    arrL_rutasComunes.add( encontrarRuta( int_almacenInicioR, arrL_rutas ) );
                }
                if( arrL_rutasComunes.size() > 0 ){
                    arrL_retVal.add(unificaRuta(arrL_rutasComunes,arrL_retVal));
                    agregaRutasSimples( arrL_retVal, arrL_rutas );
                    arrL_rutas = (ArrayList)arrL_retVal.clone();
                }
            }
        }
        agregaRutasSimples( arrL_retVal, arrL_rutas );
        return arrL_retVal;
    }

    private int encontrarInicioRuta( int int_idAlmacen, int int_hijo ){
        int int_retVal = -1;
        Iterator itr_almacenes = Arrays.asList(almacenes).iterator();
        while( itr_almacenes.hasNext() ){
            AlmacenNode nodo_tmp = (AlmacenNode)itr_almacenes.next();
            if( nodo_tmp.idAlmacen() == int_idAlmacen ){
                if( nodo_tmp.tipo() == AlmacenNode.RAIZ ){
                    int_retVal = int_hijo;
                    break;
                }else{
                    Iterator itr_almOrigen = Arrays.asList(nodo_tmp.almacenesOrigen()).iterator();
                    if( itr_almOrigen.hasNext() ){
                        int_retVal = encontrarInicioRuta( ((AlmacenOrigen)itr_almOrigen.next()).idAlmacen(), nodo_tmp.idAlmacen() );
                    }
                }
            }
        }
        return int_retVal;
    }

    private Object [] encontrarRuta( int int_almacenInicioRuta, ArrayList arrL_anterior ){
        Object obj_retVal = null;
        Iterator itr_tmp = arrL_anterior.iterator();
        cod_principal: while( itr_tmp.hasNext() ){
            Object [] objs_ruta = (Object [])itr_tmp.next();
            Iterator itr_nodosOrigen = Arrays.asList((Object [])objs_ruta[0]).iterator();
            while( itr_nodosOrigen.hasNext() ){
                AlmacenNode nodo_tmp = (AlmacenNode)itr_nodosOrigen.next();
                if( nodo_tmp.idAlmacen() == int_almacenInicioRuta ){
                    obj_retVal = objs_ruta;
                    break cod_principal;
                }
            }
        }
        return (Object [])obj_retVal;
    }

    private Object [] unificaRuta( ArrayList arrL_rutasComunes, ArrayList arrL_nuevas ){
        Object obj_retVal = null;
        Iterator itr_tmp = arrL_rutasComunes.iterator();
        ArrayList arrL_nodos = new ArrayList();
        ArrayList arrL_rutas = new ArrayList();
        double dbl_toneladasOrigen = 0;
        while( itr_tmp.hasNext() ){
            Object [] objs_rutaOrigen = (Object [])itr_tmp.next();
            Iterator itr_nodos = Arrays.asList((Object [])objs_rutaOrigen[0]).iterator();
            while( itr_nodos.hasNext() ){
                AlmacenNode nodo_tmp = (AlmacenNode)itr_nodos.next();
                arrL_nodos.add(nodo_tmp);
                borrarNodoAnt( arrL_nuevas, nodo_tmp.idAlmacen() );
            }
            dbl_toneladasOrigen += ((Double)objs_rutaOrigen[1]).doubleValue();
            Iterator itr_rutas = Arrays.asList((Object [])objs_rutaOrigen[2]).iterator();
            while( itr_rutas.hasNext() ){
                arrL_rutas.add(itr_rutas.next());
            }
        }
        Object [] objs_rutaOrigenUnificada = {arrL_nodos.toArray(), new Double(dbl_toneladasOrigen), arrL_rutas.toArray()};
        obj_retVal = objs_rutaOrigenUnificada;
        return (Object [])obj_retVal;
    }

    private void agregaRutasSimples( ArrayList arrL_rutasNuevas, ArrayList arrL_rutasAnteriores ){
        Iterator itr_tmp = arrL_rutasAnteriores.iterator();
        while( itr_tmp.hasNext() ){
            Object [] objs_nodoPri = (Object [])itr_tmp.next();
            Iterator itr_rutaAnt = Arrays.asList((Object [])objs_nodoPri[0] ).iterator();
            boolean bol_encontrado = false;
            cod_rutasAnt: while( itr_rutaAnt.hasNext() ){
                AlmacenNode nodo_tmp = (AlmacenNode)itr_rutaAnt.next();
                Iterator itr_nodosNvo = arrL_rutasNuevas.iterator();
                while( itr_nodosNvo.hasNext() ){
                    Object [] objs_nodosNvo = (Object [])itr_nodosNvo.next();
                    Iterator itr_nodosUni = Arrays.asList( (Object [])objs_nodosNvo[0] ).iterator();
                    while( itr_nodosUni.hasNext() ){
                        AlmacenNode nodo_uni = (AlmacenNode)itr_nodosUni.next();
                        if( nodo_tmp.idAlmacen() == nodo_uni.idAlmacen() ){
                            bol_encontrado = true;
                            break cod_rutasAnt;
                        }
                    }
                }
            }
            if( !bol_encontrado ){
                arrL_rutasNuevas.add(objs_nodoPri);
            }

        }
    }

    private void borrarNodoAnt( ArrayList arrL_nodosOr, int int_idAlmacen ){
        Iterator itr_tmp = arrL_nodosOr.iterator();
        while( itr_tmp.hasNext() ){
            Object obj_item = itr_tmp.next();
            Object [] objs_nodosOr = (Object [])obj_item;
            Iterator itr_nodos = Arrays.asList((Object [])objs_nodosOr[0]).iterator();
            while( itr_nodos.hasNext() ){
                AlmacenNode nodo_tmp = (AlmacenNode)itr_nodos.next();
                if( nodo_tmp.idAlmacen() == int_idAlmacen ){
                    arrL_nodosOr.remove(obj_item);
                    return;
                }
            }
        }
    }
}
